import 'dart:io';
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
import 'package:gal/gal.dart';
import '../models/download_record.dart';

/// MP4直接下载服务
class Mp4DownloadService {
  final Map<String, CancelToken> _cancelTokens = {};
  final Map<String, DownloadRecord> _activeDownloads = {};
  final Map<String, DateTime> _lastProgressUpdate = {};

  /// 直接下载MP4文件
  Future<void> downloadMp4({
    required String downloadUrl,
    required String deviceName,
    required String startTime,
    required String endTime,
    required String duration,
    int? recordId,
    int? userId,
    String? deviceId,
    String? channelId,
    String? channelName,
    required Function(DownloadRecord) onProgress,
    required Function(DownloadRecord) onComplete,
    required Function(DownloadRecord, String) onError,
    required String picUrl,
  }) async {
    try {
      // 生成文件名和路径
      final fileName = _generateFileName(deviceName, startTime, endTime);
      final downloadDir = await _getDownloadDirectory();
      final outputPath = path.join(downloadDir, fileName);

      print('🎬 MP4下载开始: $deviceName');
      print('📁 下载URL: $downloadUrl');
      print('📁 保存路径: $outputPath');

      // 创建下载记录
      final record = DownloadRecord(
        id: recordId,
        userId: userId ?? 0, // 使用传入的userId，如果为null则使用0
        deviceId: deviceId ?? '',
        deviceName: deviceName,
        channelId: channelId ?? '',
        channelName: channelName ?? deviceName,
        videoUrl: downloadUrl,
        localPath: outputPath,
        fileName: fileName,
        startTime: startTime,
        endTime: endTime,
        duration: duration,
        fileSize: '0B',
        downloadedSize: '0B',
        progress: 0.0,
        speed: '0B/s',
        status: DownloadStatus.downloading,
        createdAt: DateTime.now(),
        picUrl: picUrl,
      );

      // 添加到活动下载列表
      _activeDownloads[downloadUrl] = record;

      // 创建取消令牌
      final cancelToken = CancelToken();
      _cancelTokens[downloadUrl] = cancelToken;

      // 开始下载
      await _downloadFile(
        downloadUrl: downloadUrl,
        outputPath: outputPath,
        record: record,
        cancelToken: cancelToken,
        onProgress: onProgress,
        onComplete: onComplete,
        onError: onError,
      );
    } catch (e) {
      print('❌ MP4下载失败: $e');
      rethrow;
    }
  }

  /// 下载文件
  Future<void> _downloadFile({
    required String downloadUrl,
    required String outputPath,
    required DownloadRecord record,
    required CancelToken cancelToken,
    required Function(DownloadRecord) onProgress,
    required Function(DownloadRecord) onComplete,
    required Function(DownloadRecord, String) onError,
  }) async {
    try {
      int downloadedBytes = 0;
      final startTime = DateTime.now();

      // 配置Dio以优化下载速度
      final dio = Dio();
      dio.options.connectTimeout = Duration(seconds: 30);
      dio.options.receiveTimeout = Duration(seconds: 60);
      dio.options.sendTimeout = Duration(seconds: 30);

      // 设置并发连接数
      dio.options.maxRedirects = 5;

      // 添加请求头以处理认证和重定向
      dio.options.headers = {
        'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        'Accept': '*/*',
        'Accept-Encoding': 'gzip, deflate',
        'Connection': 'keep-alive',
      };

      print('🔍 开始下载前检查:');
      print('  URL: $downloadUrl');
      print('  保存路径: $outputPath');

      // 先测试URL是否可访问
      try {
        final response = await dio.head(downloadUrl);
        print('🔍 HEAD请求响应:');
        print('  状态码: ${response.statusCode}');
        print('  内容类型: ${response.headers['content-type']}');
        print('  内容长度: ${response.headers['content-length']}');

        if (response.statusCode != 200) {
          throw Exception('URL不可访问，状态码: ${response.statusCode}');
        }

        final contentLength = response.headers['content-length']?.first;
        if (contentLength != null) {
          final expectedSize = int.tryParse(contentLength) ?? 0;
          print('📊 预期文件大小: ${_formatBytes(expectedSize)}');

          if (expectedSize < 1024) {
            // 小于1KB可能是错误页面
            throw Exception('文件大小异常，可能不是有效的视频文件');
          }
        }
      } catch (e) {
        print('⚠️ URL预检查失败: $e');
        // 继续尝试下载，但记录警告
      }

      await dio.download(
        downloadUrl,
        outputPath,
        cancelToken: cancelToken,
        onReceiveProgress: (received, total) {
          // 首先检查取消令牌
          if (cancelToken.isCancelled) {
            print('⏸️ 下载已被取消，停止进度更新');
            return;
          }

          // 检查活动下载记录是否还存在（可能被删除）
          if (!_activeDownloads.containsKey(downloadUrl)) {
            print('🗑️ 下载记录已被删除，停止进度更新');
            return;
          }

          downloadedBytes = received;
          final progress = total > 0 ? received / total : 0.0;
          final elapsed = DateTime.now().difference(startTime).inSeconds;
          final speed = elapsed > 0 ? received / elapsed : 0;

          // 使用时间间隔控制，避免过于频繁的UI更新
          final now = DateTime.now();
          final lastUpdate = _lastProgressUpdate[downloadUrl];

          // 只在以下情况更新：
          // 2. 进度变化超过15%
          // 3. 距离上次更新超过3秒
          if (received == total ||
              progress - record.progress > 0.15 ||
              lastUpdate == null ||
              now.difference(lastUpdate).inSeconds > 3) {
            final updatedRecord = record.copyWith(
              progress: progress,
              downloadedSize: _formatBytes(downloadedBytes),
              fileSize: total > 0 ? _formatBytes(total) : '未知',
              speed: '${_formatBytes(speed.toInt())}/s',
            );

            // 再次检查取消状态
            if (!cancelToken.isCancelled &&
                _activeDownloads.containsKey(downloadUrl)) {
              onProgress(updatedRecord);
              _activeDownloads[downloadUrl] = updatedRecord;
              _lastProgressUpdate[downloadUrl] = now;
            }
          }
        },
      );

      // 检查下载是否被取消
      if (cancelToken.isCancelled) {
        // 检查是否是暂停操作
        final activeRecord = _activeDownloads[downloadUrl];
        final isPaused = activeRecord?.status == DownloadStatus.paused;

        if (isPaused) {
          print('⏸️ MP4下载被暂停: ${record.deviceName}');
          // 通知controller更新为暂停状态
          if (activeRecord != null) {
            onProgress(activeRecord);
          }
        } else {
          print('❌ MP4下载被取消: ${record.deviceName}');
        }

        // 清理资源
        _activeDownloads.remove(downloadUrl);
        _cancelTokens.remove(downloadUrl);
        return;
      }

      // 获取文件信息
      final file = File(outputPath);
      if (!await file.exists()) {
        throw Exception('下载的文件不存在');
      }

      final fileSize = await file.length();

      // 验证下载的文件是否有效
      if (fileSize < 1024) {
        // 小于1KB
        print('❌ 下载的文件大小异常: ${_formatBytes(fileSize)}');
        throw Exception('下载的文件大小异常，可能不是有效的视频文件');
      }

      // 检查文件内容类型（简单检查文件头）
      try {
        final bytes = await file.readAsBytes();
        if (bytes.length >= 4) {
          // 检查MP4文件头 (ftyp)
          final header = String.fromCharCodes(bytes.take(4));
          if (header != 'ftyp' && !bytes.take(4).any((b) => b == 0x00)) {
            print('⚠️ 文件可能不是有效的MP4格式');
          }
        }
      } catch (e) {
        print('⚠️ 文件内容检查失败: $e');
      }

      // 额外保存一份到公共下载目录
      await _saveToPublicDirectory(outputPath);

      // 额外保存一份到相册
      await _saveToAlbum(outputPath);

      final finalRecord = record.copyWith(
        status: DownloadStatus.completed,
        progress: 1.0,
        localPath: outputPath,
        fileName: path.basename(outputPath),
        downloadedSize: _formatBytes(fileSize),
        fileSize: _formatBytes(fileSize),
        updatedAt: DateTime.now(),
      );

      print('📝 MP4下载记录完成: ${finalRecord.deviceName}');
      onComplete(finalRecord);

      // 清理
      _activeDownloads.remove(downloadUrl);
      _cancelTokens.remove(downloadUrl);
    } catch (e) {
      // 检查是否是暂停操作导致的取消
      final activeRecord = _activeDownloads[downloadUrl];
      final isPaused = activeRecord?.status == DownloadStatus.paused;

      if (isPaused) {
        // 如果是暂停操作，不触发onError，而是触发onProgress更新为paused状态
        print('⏸️ 下载因暂停操作而停止: ${activeRecord?.deviceName}');
        if (activeRecord != null) {
          onProgress(activeRecord); // 通知controller更新为暂停状态
        }
      } else {
        // 否则是真正的下载失败
        print('❌ MP4文件下载失败: $e');

        final errorRecord = record.copyWith(
          status: DownloadStatus.failed,
          errorMessage: e.toString(),
          updatedAt: DateTime.now(),
        );

        onError(errorRecord, e.toString());
      }

      // 清理
      _activeDownloads.remove(downloadUrl);
      _cancelTokens.remove(downloadUrl);
    }
  }

  /// 暂停下载
  void pauseDownload(String downloadUrl) {
    print('⏸️ 暂停MP4下载: $downloadUrl');

    // 先更新记录状态为paused（这样catch块可以识别是暂停操作）
    final record = _activeDownloads[downloadUrl];
    if (record != null) {
      final updatedRecord = record.copyWith(
        status: DownloadStatus.paused,
        updatedAt: DateTime.now(),
      );
      _activeDownloads[downloadUrl] = updatedRecord;
      print('✅ MP4下载状态已更新为暂停: ${record.deviceName}');
    }

    // 然后取消下载
    final cancelToken = _cancelTokens[downloadUrl];
    if (cancelToken != null && !cancelToken.isCancelled) {
      cancelToken.cancel('用户暂停下载');
      print('✅ 下载令牌已取消');
    }
  }

  /// 取消下载
  void cancelDownload(String downloadUrl) {
    print('❌ 取消MP4下载: $downloadUrl');

    final cancelToken = _cancelTokens[downloadUrl];
    if (cancelToken != null && !cancelToken.isCancelled) {
      cancelToken.cancel('用户取消下载');
    }

    // 移除活动下载记录
    _activeDownloads.remove(downloadUrl);
    _cancelTokens.remove(downloadUrl);

    print('✅ MP4下载已取消: $downloadUrl');
  }

  /// 🚫 强制移除活动下载记录（用于删除时彻底清理）
  void forceRemoveActiveDownload(String downloadUrl) {
    print('🚫 强制移除MP4活动下载记录: $downloadUrl');

    final cancelToken = _cancelTokens[downloadUrl];
    if (cancelToken != null && !cancelToken.isCancelled) {
      cancelToken.cancel('记录被删除');
    }

    // 获取记录信息用于日志
    final record = _activeDownloads[downloadUrl];
    if (record != null) {
      print('🗑️ 移除MP4活动下载记录: ${record.deviceName} (ID: ${record.id})');
    }

    // 完全移除相关记录
    _activeDownloads.remove(downloadUrl);
    _cancelTokens.remove(downloadUrl);

    print('✅ MP4活动下载记录已强制移除: $downloadUrl');
  }

  /// 获取下载目录（内部存储）
  Future<String> _getDownloadDirectory() async {
    final directory = await getApplicationDocumentsDirectory();
    final downloadDir = Directory('${directory.path}/downloads');
    if (!await downloadDir.exists()) {
      await downloadDir.create(recursive: true);
    }
    print('📁 使用内部存储下载目录: ${downloadDir.path}');
    return downloadDir.path;
  }

  /// 生成文件名（确保唯一性）
  String _generateFileName(
    String deviceName,
    String startTime,
    String endTime,
  ) {
    try {
      // 解析时间字符串，转换为北京时间
      DateTime startDateTime = DateTime.parse(startTime);
      DateTime endDateTime = DateTime.parse(endTime);

      // 格式化为北京时间：MM月DD日 HH:mm
      String startFormatted =
          '${startDateTime.month.toString().padLeft(2, '0')}月${startDateTime.day.toString().padLeft(2, '0')}日 ${startDateTime.hour.toString().padLeft(2, '0')}:${startDateTime.minute.toString().padLeft(2, '0')}';
      String endFormatted =
          '${endDateTime.hour.toString().padLeft(2, '0')}:${endDateTime.minute.toString().padLeft(2, '0')}';

      // 清理设备名称，移除特殊字符
      final sanitizedDeviceName = deviceName.replaceAll(
        RegExp(r'[^\w\s-]'),
        '',
      );

      // 添加时间戳确保文件名唯一性
      final timestamp = DateTime.now().millisecondsSinceEpoch;

      // 生成唯一的文件名：时间戳_设备名_日期_时间.mp4
      if (startDateTime.year == endDateTime.year &&
          startDateTime.month == endDateTime.month &&
          startDateTime.day == endDateTime.day) {
        return '${timestamp}_${sanitizedDeviceName}_${startFormatted}-${endFormatted}.mp4';
      } else {
        // 如果跨天，显示两个日期
        String endDateFormatted =
            '${endDateTime.month.toString().padLeft(2, '0')}月${endDateTime.day.toString().padLeft(2, '0')}日 ${endDateTime.hour.toString().padLeft(2, '0')}:${endDateTime.minute.toString().padLeft(2, '0')}';
        return '${timestamp}_${sanitizedDeviceName}_${startFormatted}-${endDateFormatted}.mp4';
      }
    } catch (e) {
      print('⚠️ 时间解析失败，使用原始格式: $e');
      // 如果时间解析失败，回退到简化格式
      final startTimeFormatted = startTime.replaceAll('T', ' ').split('.')[0];
      final endTimeFormatted = endTime.replaceAll('T', ' ').split('.')[0];
      final sanitizedDeviceName = deviceName.replaceAll(
        RegExp(r'[^\w\s-]'),
        '',
      );
      final timestamp = DateTime.now().millisecondsSinceEpoch;
      return '${timestamp}_${sanitizedDeviceName}_${startTimeFormatted}-${endTimeFormatted}.mp4';
    }
  }

  /// 格式化字节数
  String _formatBytes(int bytes) {
    if (bytes < 1024) return '${bytes}B';
    if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)}KB';
    if (bytes < 1024 * 1024 * 1024)
      return '${(bytes / (1024 * 1024)).toStringAsFixed(1)}MB';
    return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(1)}GB';
  }

  /// 额外保存文件到公共目录
  Future<void> _saveToPublicDirectory(String filePath) async {
    try {
      print('📁 开始额外保存MP4文件到公共下载目录...');

      // 检查文件是否存在
      final file = File(filePath);
      if (!await file.exists()) {
        print('⚠️ 文件不存在，跳过公共目录保存: $filePath');
        return;
      }

      // 验证文件大小和内容
      final fileSize = await file.length();
      if (fileSize < 1024) {
        print('⚠️ 文件大小异常，跳过公共目录保存: ${_formatBytes(fileSize)}');
        return;
      }

      // 验证文件是否为有效的MP4文件
      try {
        final bytes = await file.readAsBytes();
        if (bytes.length < 8) {
          print('⚠️ 文件内容异常，跳过公共目录保存');
          return;
        }

        // 检查MP4文件头
        final header = String.fromCharCodes(bytes.take(4));
        if (header != 'ftyp') {
          print('⚠️ 文件不是有效的MP4格式，跳过公共目录保存');
          return;
        }
      } catch (e) {
        print('⚠️ 文件验证失败，跳过公共目录保存: $e');
        return;
      }

      // 检查gal权限
      final hasAccess = await Gal.hasAccess(toAlbum: false);
      if (!hasAccess) {
        print('🔑 请求存储权限...');
        final requestResult = await Gal.requestAccess(toAlbum: false);
        if (!requestResult) {
          print('❌ 存储权限被拒绝，跳过公共目录保存');
          return;
        }
      }

      print('✅ 存储权限检查通过，文件验证通过');

      // 使用Gal保存视频文件到公共下载目录
      await Gal.putVideo(filePath);
      print('✅ MP4文件已额外保存到公共下载目录');
      print('📁 用户可在文件管理器的"下载"文件夹中找到该文件');
    } on GalException catch (e) {
      print('💥 Gal插件异常: ${e.type.message}');
      print('⚠️ 公共目录保存失败，但内部存储文件正常');
    } catch (e) {
      print('❌ 公共目录保存失败: $e');
      print('⚠️ 内部存储文件正常，用户仍可通过应用播放');
    }
  }

  /// 额外保存文件到相册
  Future<void> _saveToAlbum(String filePath) async {
    try {
      print('📸 开始额外保存MP4文件到相册...');

      // 检查文件是否存在
      final file = File(filePath);
      if (!await file.exists()) {
        print('⚠️ 文件不存在，跳过相册保存: $filePath');
        return;
      }

      // 验证文件大小和内容
      final fileSize = await file.length();
      if (fileSize < 1024) {
        print('⚠️ 文件大小异常，跳过相册保存: ${_formatBytes(fileSize)}');
        return;
      }

      // 检查gal权限（相册权限）
      final hasAccess = await Gal.hasAccess(toAlbum: true);
      if (!hasAccess) {
        print('🔑 请求相册权限...');
        final requestResult = await Gal.requestAccess(toAlbum: true);
        if (!requestResult) {
          print('❌ 相册权限被拒绝，跳过相册保存');
          return;
        }
      }

      print('✅ 相册权限检查通过，文件验证通过');

      // 使用Gal保存视频文件到相册
      // 注意：Gal.putVideo 在请求相册权限后会保存到相册
      await Gal.putVideo(filePath);
      print('✅ MP4文件已额外保存到相册');
      print('📸 用户可在相册中找到该视频文件');
    } on GalException catch (e) {
      print('💥 Gal插件异常: ${e.type.message}');
      print('⚠️ 相册保存失败，但内部存储文件正常');
    } catch (e) {
      print('❌ 相册保存失败: $e');
      print('⚠️ 内部存储文件正常，用户仍可通过应用播放');
    }
  }

  /// 获取活动下载列表
  List<DownloadRecord> getActiveDownloads() {
    return _activeDownloads.values.toList();
  }

  /// 清理所有下载
  void dispose() {
    for (final cancelToken in _cancelTokens.values) {
      if (!cancelToken.isCancelled) {
        cancelToken.cancel('服务关闭');
      }
    }
    _cancelTokens.clear();
    _activeDownloads.clear();
  }
}
